package cn.sample.security.manager;

import cn.sample.common.properties.SysProperties;
import cn.sample.system.bean.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.function.Supplier;

/**
 * <h2></h2>
 *
 * <p>自定义请求授权管理器</p>
 *
 * @author HKD
 */
@Component
public class RequestAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Resource
    private SysProperties sysProperties;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
        // 处理用户认证是否符合权限
        boolean granted = isGranted(authentication.get(),requestAuthorizationContext.getRequest());
        return new AuthorizationDecision(granted);
    }

    private boolean isGranted(Authentication authentication, HttpServletRequest request) {
        return authentication != null && isAuthorized(authentication,request);
    }

    /**
     * 处理授权核心方法，返回 true 表示可以访问，返回 false 表示拒绝访问
     */
    private boolean isAuthorized(Authentication authentication,HttpServletRequest request) {
        String principal = (String) authentication.getPrincipal();
        if(StringUtils.equals(principal,"anonymousUser")){ // 匿名用户处理
            // 这里可以放行匿名用户也可以访问的接口
            return false;
        }

        User user = (User) authentication.getDetails();

        // 获取用户接口权限和请求路径匹配
        String resCacheKey = StringUtils.join(sysProperties.getProject(),":system:res:",user.getUsername());
        List<cn.sample.system.bean.Resource> resourceList = (List<cn.sample.system.bean.Resource>) redisTemplate.opsForValue().get(resCacheKey);

        if(resourceList == null){
            return false;
        }

        // 如果用户匹配我们就通过请求
        boolean anyMatch = resourceList.stream().anyMatch(resource -> {
            if (resource.getResource().equals(request.getRequestURI())) {
                return true;
            }
            return false;
        });

        return anyMatch;
    }


}
